import { EventDispatcher } from './dispatcher';

export class WebSocketClient extends EventDispatcher {
  // #发送心跳数据间隔
  private heartbeatInterval = 1000 * 30;
  // #计时器id
  private heartbeatTimer?: NodeJS.Timeout;
  // #最大重连数
  private maxReconnectionAttempts = 5;
  // #重连次数
  private reconnectAttempts = 0;
  // #重连间隔
  private reconnectInterval = 10_000; // 10 seconds
  // #彻底终止ws
  private stopWs = false;
  // 连接状态
  public readyState: number = WebSocket.CLOSED;
  // #socket实例
  public socket: null | WebSocket = null;
  // #socket链接
  public url = '';
  // *构造函数
  constructor(url: string) {
    super();
    this.url = url;
  }
  // >关闭心跳
  private closeHeartbeat(): void {
    clearInterval(this.heartbeatTimer);
    this.heartbeatTimer = undefined;
  }
  // > 断网重连逻辑
  private handleReconnect(): void {
    if (this.reconnectAttempts < this.maxReconnectionAttempts) {
      this.reconnectAttempts += 1;
      this.log(
        'WebSocket',
        `尝试重连... (${this.reconnectAttempts}/${this.maxReconnectionAttempts})       ${this.url}`,
      );
      setTimeout(() => {
        this.connect();
      }, this.reconnectInterval);
    } else {
      this.closeHeartbeat();
      this.log('WebSocket', `最大重连失败，终止重连: ${this.url}`);
    }
  }
  // >开始心跳检测 -> 定时发送心跳消息
  private startHeartbeat(): void {
    if (this.stopWs) return;
    if (this.heartbeatTimer) {
      this.closeHeartbeat();
    }
    this.heartbeatTimer = setInterval(() => {
      if (this.socket) {
        // this.socket.send(JSON.stringify({ data: {}, type: 'heartBeat' }));
        this.log('WebSocket', '发送心跳数据...');
      } else {
        console.error('[WebSocket] 未连接');
      }
    }, this.heartbeatInterval);
  }
  // >关闭连接
  public close(): void {
    if (this.socket) {
      this.stopWs = true;
      this.socket.close();
      this.socket = null;
      this.readyState = WebSocket.CLOSED;
      this.removeEventListener('open');
      this.removeEventListener('message');
      this.removeEventListener('close');
      this.removeEventListener('error');
    }
    this.closeHeartbeat();
  }
  // !初始化连接
  public connect(): void {
    if (this.reconnectAttempts === 0) {
      this.log('WebSocket', `初始化连接中...          ${this.url}`);
    }
    console.log('WebSocket', this.socket, this.readyState, '未连接');
    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
      this.readyState = WebSocket.OPEN;
      return;
    }
    this.socket = new WebSocket(this.url);
    console.log('WebSocket', this.socket, this.readyState, '已连接');

    // !websocket连接成功
    this.socket.addEventListener('open', (event) => {
      this.stopWs = false;
      // 重置重连尝试成功连接
      this.reconnectAttempts = 0;
      // 在连接成功时停止当前的心跳检测并重新启动
      this.startHeartbeat();
      this.log(
        'WebSocket',
        `连接成功,等待服务端数据推送[onopen]...     ${this.url}`,
      );
      this.dispatchEvent('open', event);
      this.readyState = WebSocket.OPEN;
    });

    this.socket.addEventListener('message', (event) => {
      this.dispatchEvent('message', event);
      this.startHeartbeat();
    });

    this.socket.addEventListener('close', (event) => {
      if (this.reconnectAttempts === 0) {
        this.log('WebSocket', `连接断开[onclose]...    ${this.url}`);
        this.readyState = WebSocket.CLOSED;
      }
      if (!this.stopWs) {
        this.handleReconnect();
      }
      this.dispatchEvent('close', event);
    });

    this.socket.addEventListener('error', (event) => {
      if (this.reconnectAttempts === 0) {
        this.log('WebSocket', `连接异常[onerror]...    ${this.url}`);
        this.readyState = WebSocket.CONNECTING;
      }
      this.closeHeartbeat();
      this.dispatchEvent('error', event);
    });
  }

  onclose(callBack: () => void) {
    this.addEventListener('close', callBack);
  }

  onerror(callBack: () => void) {
    this.addEventListener('error', callBack);
  }

  onmessage(callBack: (data: any) => void) {
    this.addEventListener('message', callBack);
  }

  // >生命周期钩子
  onopen(callBack: () => void) {
    this.addEventListener('open', callBack);
  }

  // >消息发送
  public send(message: string): void {
    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
      this.socket.send(message);
    } else {
      console.error('[WebSocket] 未连接');
      this.readyState = WebSocket.CLOSED;
    }
  }
}
